using Joy.Erp.BasicArchives.Core;
using Joy.Erp.BasicArchives.Core.Filters;
using Joy.Erp.BasicArchives.Permissions;
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Data;
using Volo.Abp.Domain.Repositories;

namespace Joy.Erp.BasicArchives.Production
{
    [Authorize]
    public class PlanOrderAppService : BasicArchivesAppService, IPlanOrderAppService
    {
        protected IPlanOrderRepository PlanOrderRepository => LazyServiceProvider.LazyGetRequiredService<IPlanOrderRepository>();
        protected PlanOrderManager PlanOrderManager => LazyServiceProvider.LazyGetRequiredService<PlanOrderManager>();

        [Authorize(BasicArchivesPermissions.PlanOrder.Query)]
        public async Task<PlanOrderDto> GetAsync(Guid id)
        {
            var entity = await PlanOrderRepository.GetAsync(id, true);
            return ObjectMapper.Map<PlanOrder, PlanOrderDto>(entity);
        }

        [Authorize(BasicArchivesPermissions.PlanOrder.Query)]
        public async Task<PlanOrderPreparationDto> GetChildAsync(Guid id)
        {
            var child = await PlanOrderRepository.GetChildAsync(id, true);
            return ObjectMapper.Map<PlanOrderPreparation, PlanOrderPreparationDto>(child);
        }

        [Authorize(BasicArchivesPermissions.PlanOrder.Query)]
        public async Task<PlanOrderDto> FindAsync(string filter)
        {
            var entity = await PlanOrderRepository.FindAsync(x => x.Code == filter);
            return ObjectMapper.Map<PlanOrder, PlanOrderDto>(entity);
        }

        [Authorize(BasicArchivesPermissions.PlanOrder.Query)]
        public async Task<PlanOrderDto> FindBySourceKeyAsync(string sourceKey, string sourceType)
        {
            var entity = await PlanOrderRepository.FindAsync(x => x.SourceKey == sourceKey && x.SourceType == sourceType);
            return ObjectMapper.Map<PlanOrder, PlanOrderDto>(entity);
        }

        [Authorize(BasicArchivesPermissions.PlanOrder.Query)]
        public async Task<PagedResultDto<PlanOrderDto>> GetListAsync(FilterRequestDto input)
        {
            var totalCount = await PlanOrderRepository.GetCountAsync(input.Filter, true);
            var list = await PlanOrderRepository.GetPagedListAsync(input.Filter, input.SkipCount, input.MaxResultCount, input.Sorting, true);

            return new PagedResultDto<PlanOrderDto>(
                totalCount,
                ObjectMapper.Map<List<PlanOrder>, List<PlanOrderDto>>(list));
        }

        [Authorize(BasicArchivesPermissions.PlanOrder.Query)]
        public async Task<PagedResultDto<PlanOrderDto>> QueryAsync(FilterGroupRequestDto input)
        {
            Expression<Func<PlanOrder, bool>> expression = null;
            if (input != null && input.FilterGroup != null)
            {
                expression = FilterConverter.Convert<PlanOrder>(input.FilterGroup);
            }

            var totalCount = await PlanOrderRepository.GetCountAsync(expression, true);
            var list = await PlanOrderRepository.GetPagedListAsync(expression, input.SkipCount, input.MaxResultCount, input.Sorting, true);

            return new PagedResultDto<PlanOrderDto>(
                totalCount,
                ObjectMapper.Map<List<PlanOrder>, List<PlanOrderDto>>(list));
        }

        [Authorize(BasicArchivesPermissions.PlanOrder.Query)]
        public async Task<PagedResultDto<PlanOrderPreparationDto>> QueryChildrenAsync(FilterGroupRequestDto input)
        {
            Expression<Func<PlanOrderPreparation, bool>> expression = null;
            if (input != null && input.FilterGroup != null)
            {
                expression = FilterConverter.Convert<PlanOrderPreparation>(input.FilterGroup);
            }

            var totalCount = await PlanOrderRepository.GetChildrenCountAsync(expression, true);
            var list = await PlanOrderRepository.GetChildrenPagedListAsync(expression, input.SkipCount, input.MaxResultCount, input.Sorting, true);

            return new PagedResultDto<PlanOrderPreparationDto>(
                totalCount,
                ObjectMapper.Map<List<PlanOrderPreparation>, List<PlanOrderPreparationDto>>(list));
        }

        [Authorize(BasicArchivesPermissions.PlanOrder.Create)]
        public async Task<PlanOrderDto> CreateAsync(PlanOrderCreateDto input)
        {
            var entity = ObjectMapper.Map<PlanOrderCreateDto, PlanOrder>(input);

            await PlanOrderManager.CreateAsync(entity, true);
            return await GetAsync(entity.Id);
        }

        [Authorize(BasicArchivesPermissions.PlanOrder.Update)]
        public async Task<PlanOrderDto> UpdateAsync(Guid id, PlanOrderUpdateDto input)
        {
            var entity = await PlanOrderRepository.GetAsync(id, true);
            entity.SetConcurrencyStampIfNotNull(input.ConcurrencyStamp);

            await PlanOrderRepository.EnsureCollectionLoadedAsync(entity, x => x.Children);
            ObjectMapper.Map(input, entity);

            await PlanOrderManager.UpdateAsync(entity, true);
            return await GetAsync(entity.Id);
        }

        [Authorize(BasicArchivesPermissions.PlanOrder.Submit)]
        public async Task<PlanOrderDto> SubmitAsync(Guid id)
        {
            await PlanOrderManager.ChangeStatus(id, DocumentStatus.Waiting);
            return await GetAsync(id);
        }

        [Authorize(BasicArchivesPermissions.PlanOrder.Approve)]
        public async Task<PlanOrderDto> ApproveAsync(Guid id)
        {
            await PlanOrderManager.ChangeStatus(id, DocumentStatus.Approved);
            return await GetAsync(id);
        }

        [Authorize(BasicArchivesPermissions.PlanOrder.UnApprove)]
        public async Task<PlanOrderDto> UnApproveAsync(Guid id)
        {
            await PlanOrderManager.ChangeStatus(id, DocumentStatus.Open);
            return await GetAsync(id);
        }

        [Authorize(BasicArchivesPermissions.PlanOrder.Delete)]
        public async Task DeleteAsync(Guid id)
        {
            await PlanOrderManager.DeleteAsync(id);
        }
    }
}